package com.jame.context;


import com.jame.annotations.bean.Autowired;
import com.jame.annotations.bean.Scope;
import com.jame.context.definition.ConfigurationBeanDefinition;
import com.jame.context.definition.UniversalBeanDefinition;
import com.jame.exception.BeanDefinitionException;
import com.jame.exception.PrototypeInjectException;
import com.jame.exception.UniversalException;
import com.jame.typeenum.ScopeType;
import com.jame.util.StringUtil;
import org.apache.log4j.Logger;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author : Jame
 * @date : 2021-06-13 17:53
 * bean容器,创建bean的工作在这里进行
 **/
public class BeanContainer {

    /**
     * 单例-饿汉
     */
    private final static BeanContainer beanContainer = new BeanContainer();

    private BeanContainer() {
    }

    public static BeanContainer getBeanContainer() {
        return beanContainer;
    }

    private static Logger logger = Logger.getLogger(BeanContainer.class);

    //存放bean对应bean定义
    private final Map<String, UniversalBeanDefinition> beanDefinitionMap = new HashMap<>(256);

    //存放bean对应工厂
    private final Map<String, BeanFactory> beanFactoryMap = new HashMap<>(256);

    //存放实例化出的单例bean
    private final Map<String, Object> beans = new HashMap<>(256);

    //存放当前正在创建的bean,用于判断循环依赖
    private final List<String> creatingBeansList = new ArrayList<>(10);

    //存放需要增强的类名或包名
    private final List<String> executeList = new ArrayList<>(50);

    private final BeanAop beanAop = BeanAop.getBeanAop();


    public <T> T doGetBean(String beanName) {
        Object o;
        //先尝试从单例缓存中取
        o = beans.get(beanName);
        if (o == null) {
            try {
                //如果缓存中没有在去创建
                ReturnBeanType bean = createBean(beanName);
                if (bean != null) {
                    o = bean.getObject();
                    if (!bean.getSingle()) {
                        beanFactoryMap.remove(beanName);
                    }
                }
            } catch (IllegalAccessException | InstantiationException | UniversalException e) {
                e.printStackTrace();
            }
            //清空当前正在创建的bean集合
            creatingBeansList.clear();
        }
        return (T) o;
    }

    public ReturnBeanType createBean(String beanName) throws IllegalAccessException, InstantiationException, UniversalException {
        UniversalBeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

        if (beanDefinition == null) {
            throw new BeanDefinitionException("没有找到类名称为" + beanName + "对应bean的定义");
        }
        //懒加载情况
        if (beanDefinition.isLazyLoad() && beanDefinition.getObject() == null) {
            Object o = beanDefinition.getInterfaceClass().newInstance();
            beanDefinition.setObject(o);
        }

        /** 如果正在创建的bean集合中存在当前正在创建的bean
         *  说明出现循环依赖
         *  首先尝试从beanFactory中获取半成品bean
         */
        if (creatingBeansList.contains(beanName)) {
            BeanFactory beanFactory = beanFactoryMap.get(beanName);
            if (beanFactory != null) {
                Object bean = beanFactory.getBean();
                Scope scope = bean.getClass().getAnnotation(Scope.class);
                if (scope == null || scope.scopeType() == ScopeType.Singleton) {
                    return new ReturnBeanType(bean, true);
                }
            }
        }
        //用于递归的返回对象,以及判断上一个依赖的对象是不是单例类型
        ReturnBeanType returnBeanType = new ReturnBeanType(true);
        Object object = beanDefinition.getObject();
        Object parameter;
        //获取当前正在创建类中的所有属性
        Field[] fields = object.getClass().getDeclaredFields();
        //单例模式
        if (beanDefinition.getScopeType() == ScopeType.Singleton) {
            object = isEnhance(object);
            for (Field field : fields) {
                Autowired annotation = field.getAnnotation(Autowired.class);
                if (annotation != null) {
                    if (!field.isAccessible()) {
                        field.setAccessible(true);
                    }
                    //先尝试从factory中获取没有完成属性注入的空bean
                    BeanFactory beanFactory = beanFactoryMap.get(field.getType().getSimpleName());
                    if (beanFactory != null) {
                        parameter = beanFactory.getBean();
                    } else {
                        //将当前创建出的对象放入正在创建集合
                        creatingBeansList.add(beanName);
                        //提前曝光bean
                        beanFactoryMap.put(beanName, new BeanFactory(object));
                        //如果还没有创建,则递归调用创建bean的方法
                        ReturnBeanType type = createBean(field.getType().getSimpleName());
                        parameter = type.getObject();
                        if (!returnBeanType.getSingle())
                            returnBeanType.setSingle(type.getSingle());
                    }
                    field.set(object, parameter);
                }
            }
            returnBeanType.setObject(object);
            //原型
        } else if (beanDefinition.getScopeType() == ScopeType.Prototype) {
            object = isEnhance(beanDefinition.getInterfaceClass().newInstance());
            for (Field field : fields) {
                Autowired annotation = field.getAnnotation(Autowired.class);
                if (annotation != null) {
                    if (!field.isAccessible()) {
                        field.setAccessible(true);
                    }
                    UniversalBeanDefinition definition = beanDefinitionMap.get(field.getType().getSimpleName());
                    if (definition == null) {
                        throw new BeanDefinitionException("没有找到类名称为" + beanName + "对应bean的定义");
                    }
                    //出现原型注入原型问题
                    if (definition.getScopeType() == ScopeType.Prototype && creatingBeansList.contains(definition.getName())) {
                        throw new PrototypeInjectException("不支持原型注入原型的循环依赖");
                    }
                    //先尝试从factory中获取没有完成属性注入的空bean
                    BeanFactory beanFactory = beanFactoryMap.get(field.getType().getSimpleName());
                    if (beanFactory != null) {
                        parameter = beanFactory.getBean();
                    } else {
                        //将当前创建出的对象放入正在创建集合
                        creatingBeansList.add(beanName);
                        //如果还没有创建,则递归调用创建bean的方法
                        ReturnBeanType type = createBean(field.getType().getSimpleName());
                        //如果等于null说明出现了原型的循环依赖或者bd没找到问题.则停止操作
                        if (type == null) {
                            return null;
                        }
                        parameter = type.getObject();
                        returnBeanType.setSingle(type.getSingle());
                    }
                    field.set(object, parameter);
                }
            }
            returnBeanType.setObject(object);
            returnBeanType.setSingle(false);
        }
        //如果bean是单例以及它的属性都是单例对象则存放缓存
        if (returnBeanType.getSingle()) {
            beans.put(beanName, object);
        }
        return returnBeanType;
    }

    /**
     * 判断是否需要增强,如果需要则直接进行
     */
    private Object isEnhance(Object o) {
        ArrayList<String> strings = new ArrayList<>();
        for (String s : executeList) {
            if (StringUtil.isExist(s, o.getClass().getName()) || s.equals("*")) {
                strings.add(s);
            }
        }
        return strings.size() == 0 ? o : beanAop.enhance(o, strings);
    }


    /**
     * 初始化通用bean
     * 即 添加扫描包下的component注解的类
     *
     * @param beanDefinitions
     */
    public void setUniversalBeanDefinition(List<UniversalBeanDefinition> beanDefinitions) {
        if (beanDefinitions != null) {
            for (UniversalBeanDefinition beanDefinition : beanDefinitions) {
                beanDefinitionMap.put(beanDefinition.getName(), beanDefinition);
            }
        }
    }

    /**
     * 初始化配置类中的bean
     * 在配置类中的@Bean
     *
     * @param beanDefinitions
     */
    public void setConfigurationBeanDefinition(List<ConfigurationBeanDefinition> beanDefinitions) {
        if (beanDefinitions != null) {
            for (ConfigurationBeanDefinition beanDefinition : beanDefinitions) {
                Method method = beanDefinition.getMethod();
                if (!method.isAccessible()) {
                    method.setAccessible(true);
                }
                try {
                    UniversalBeanDefinition universalBeanDefinition = new UniversalBeanDefinition();
                    universalBeanDefinition.setObject(method.invoke(beanDefinition.getConfigObject(), null));
                    beanDefinitionMap.put(StringUtil.getBeanName(method.getName()), universalBeanDefinition);
                } catch (InvocationTargetException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 设置需要增强的类
     *
     * @param list
     */
    public void setExecuteList(List<String> list) {
        executeList.addAll(list);
    }

}
